// Package main
// @File: main.go
// @Description:
// @Author: YaoRuiQi
// @Date: 2025/8/23 02:26

package main

import (
	"GinStandardTemplate/config"
	"GinStandardTemplate/internal/middleware"
	"GinStandardTemplate/internal/pkg/jwt"
	"GinStandardTemplate/internal/router"
	"GinStandardTemplate/utils/database"
	"GinStandardTemplate/utils/i18n"
	"GinStandardTemplate/utils/lockUtils/redisLock"
	"GinStandardTemplate/utils/logger"
	"GinStandardTemplate/utils/redisUtils"
	"context"
	"errors"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

func waitForShutdown(srv *http.Server) {
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	logger.Logger.Info("接收到中断信号或终止信号，开始结束服务")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		logger.Logger.Error("结束服务超时，强行关闭", zap.Error(err))
	} else {
		logger.Logger.Info("服务正常结束")
	}
}

func runServer() *http.Server {

	gin.SetMode(config.GlobalConfig.App.Mode)

	r := gin.New()

	// 设置全局中间件
	r.Use(
		middleware.RequestIDMiddleware(),
		middleware.I18nMiddleware(),
		middleware.AuthMiddleware(),
		middleware.GinLogger(),
		middleware.RequestContextMiddleware(),
		middleware.GinRecovery(),
	)

	// 初始化路由
	router.InitRouter(r)

	// 启动服务
	serverListenAddress := fmt.Sprintf("%s:%d", config.GlobalConfig.Server.Host, config.GlobalConfig.Server.Port)
	logger.Logger.Info(
		"启动服务",
		zap.String("name", config.GlobalConfig.App.Name),
		zap.String("server_listen_address", serverListenAddress),
	)
	server := &http.Server{
		Addr:           serverListenAddress,
		Handler:        r,
		ReadTimeout:    time.Duration(config.GlobalConfig.Server.Timeout.Read) * time.Second,
		WriteTimeout:   time.Duration(config.GlobalConfig.Server.Timeout.Write) * time.Second,
		IdleTimeout:    time.Duration(config.GlobalConfig.Server.Timeout.Idle) * time.Second,
		MaxHeaderBytes: config.GlobalConfig.Server.MaxHeader << 20,
	}
	go func() {
		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			logger.Logger.Error("服务启动失败", zap.Error(err))
		}
	}()
	return server
}

func main() {
	// 初始化全局配置
	config.InitGlobalConfigAndLog()
	defer func() {
		_ = logger.Logger.Sync()
	}()

	// 初始化国际化配置
	i18n.InitI18n()

	// 初始化JWT
	jwt.Init(config.GlobalConfig.App.SecretKey)

	// 初始化Redis
	if err := redisUtils.InitRedisClient(logger.Logger, redisUtils.Config{
		Host:               config.GlobalConfig.Redis.Host,
		Port:               config.GlobalConfig.Redis.Port,
		Password:           config.GlobalConfig.Redis.Password,
		DB:                 config.GlobalConfig.Redis.DB,
		MaxRetries:         config.GlobalConfig.Redis.MaxRetries,
		MinRetryBackoff:    time.Duration(config.GlobalConfig.Redis.MinRetryBackoff) * time.Millisecond,
		MaxRetryBackoff:    time.Duration(config.GlobalConfig.Redis.MaxRetryBackoff) * time.Millisecond,
		PoolSize:           config.GlobalConfig.Redis.PoolSize,
		MinIdleConns:       config.GlobalConfig.Redis.MinIdleConns,
		ConnMaxIdleTime:    time.Duration(config.GlobalConfig.Redis.ConnMaxIdleTime) * time.Minute,
		ReadTimeout:        time.Duration(config.GlobalConfig.Redis.ReadTimeout) * time.Second,
		WriteTimeout:       time.Duration(config.GlobalConfig.Redis.WriteTimeout) * time.Second,
		DialTimeout:        time.Duration(config.GlobalConfig.Redis.DialTimeout) * time.Second,
		PoolTimeout:        time.Duration(config.GlobalConfig.Redis.PoolTimeout) * time.Second,
		HealthCheckRetries: config.GlobalConfig.Redis.HealthCheckRetries,
		Prefix:             config.GlobalConfig.Redis.Prefix,
	}); err != nil {
		logger.Logger.Fatal("Redis初始化失败", zap.Error(err))
	}

	// 初始化锁
	redisClient := redisUtils.RedisClient.GetClient()
	if err := redisLock.InitRedisLock(logger.Logger, redisClient, config.GlobalConfig.Redis.Prefix); err != nil {
		logger.Logger.Fatal("初始化Redis锁失败", zap.Error(err))
	}

	// 初始化数据库
	dsn, err := database.BuildDSN(database.DSNConfig{
		Dialect:    config.GlobalConfig.Database.Dialect,
		Host:       config.GlobalConfig.Database.Host,
		Port:       config.GlobalConfig.Database.Port,
		User:       config.GlobalConfig.Database.Username,
		Password:   config.GlobalConfig.Database.Password,
		DBName:     config.GlobalConfig.Database.DBName,
		Charset:    config.GlobalConfig.Database.Charset,
		SSLMode:    config.GlobalConfig.Database.SSLMode,
		TimeZone:   config.GlobalConfig.Database.TimeZone,
		SQLiteFile: config.GlobalConfig.Database.SQLiteFile,
	})
	if err != nil {
		logger.Logger.Fatal("构建数据库连接地址失败", zap.Error(err))
	}
	if err := database.InitDB(logger.Logger, database.DBConfig{
		Dialect:      config.GlobalConfig.Database.Dialect,
		DSN:          dsn,
		SQLiteFile:   config.GlobalConfig.Database.SQLiteFile,
		LogLevel:     config.GlobalConfig.Database.GormLogLevel,
		MaxIdleConns: config.GlobalConfig.Database.MaxIdleConns,
		MaxOpenConns: config.GlobalConfig.Database.MaxOpenConns,
		ConnMaxLife:  time.Duration(config.GlobalConfig.Database.ConnMaxLifetime) * time.Minute,
		InitTimeout:  time.Duration(config.GlobalConfig.Database.InitTimeout) * time.Second,
	}); err != nil {
		logger.Logger.Fatal("数据库初始化失败", zap.Error(err))
	}

	// 设置数据库
	// TODO: 需要使用gen生成代码后使用
	//repository.SetDefault(database.DB)

	server := runServer()

	waitForShutdown(server)
}
